from data import Data


# 编号必须和顺序对应M1代表第1台机器，机器中的零件顺序要按时序排好
# A1中的A代表第一个零件、1代表第一个零件的第一道工序
class Verifier:
    def __init__(self, data_path='data.txt'):
        self.data = Data(data_path=data_path)
        self.sol = None

    def get_sol(self, data_path='data.out'):
        f = open(data_path, 'r', encoding='utf-8')
        text = f.readlines()
        sol = list()
        for i in range(len(text)):
            if text[i][0] != 'M':
                continue
            sol.append(list())
        for i in range(len(sol)):
            temp_s = text[i].strip().split(':')
            machine_id = int(temp_s[0].replace('M', ''))
            assert machine_id == i + 1, 'Mx must be equal to row number!'
            s = temp_s[1].replace('(', '').replace(')', '').split(',')
            if len(s) == 1 and s[0] == '':
                continue
            assert len(s) % 4 == 0, 'column number is wrong!'
            for j in range(len(s) // 4):
                name = s[j * 4]
                idx = int(name.replace('S', '')) - 1
                step_idx = int(s[j * 4 + 1].replace(name, '')) - 1
                sol[i].append((idx, step_idx, int(s[j * 4 + 2]), int(s[j * 4 + 3])))
        return sol
    
    def load_sol_from_file(self, data_path='data.out'):
        self.sol = self.get_sol(data_path=data_path)

    # sol: [M1, M2, ...], M1:[(A, A1, 开始时间，结束时间), (A, A2, 开始时间，结束时间), ...]
    # A: 零件下标(0,1,2,...) A1:零件步骤下标(0,1,2,...)
    def load_sol_from_param(self, sol):
        self.sol = sol

    def _letter_to_idx(self, c):
        if c >= 'a' and c <= 'z':
            return 26 + ord(c) - ord('a')
        elif c >= 'A' and c <= 'Z':
            return ord(c) - ord('A')
        return ord(c) + 52

    def _idx_to_letter(self, idx):
        return str(idx + 1) 

    def verify(self, show_info=True):
        assert self.sol is not None, 'need load solution before verify!'
        component_num = self.data.n
        machine_num = self.data.m
        component_info = self.data.a
        # 机器数量、零件数量、步骤数量
        assert len(self.sol) == machine_num, 'machine_num(%d) need be equal to solution\'s(%d)!' % (machine_num, len(self.sol))
        for i in range(len(self.sol)):
            for j in range(len(self.sol[i])):
                assert self.sol[i][j][0] < component_num, '%s isn\'t in component_num range!' % self._idx_to_letter(self.sol[i][j][0])
                assert self.sol[i][j][1] < len(component_info[self.sol[i][j][0]]), \
                    '%s doesn\'t have step %d!' % (self._idx_to_letter(self.sol[i][j][0]), self.sol[i][j][1] + 1)
        # 机器加工时刻非负
        for i in range(machine_num):
            if len(self.sol[i]) > 0:
                assert self.sol[i][0][2] >= 0, 'machine M%d start time must not be negative!' % (i + 1)
        # 机器时序性、重复占用
        for i in range(machine_num):
            now = 0
            for j in range(len(self.sol[i])):
                assert self.sol[i][j][2] >= now, 'machine M%d period %d start time %d conflicts with last time %d!' % (i + 1, j + 1, self.sol[i][j][2], now)
                assert self.sol[i][j][3] >= self.sol[i][j][2], 'machine M%d period %d end time %d conflicts with start time %d' % (i + 1, j + 1, self.sol[i][j][3], self.sol[i][j][2])
                now = self.sol[i][j][3]
        # 零件步骤完整
        component_list = [[list() for _ in range(len(component_info[i]))] for i in range(component_num)]
        for i in range(machine_num):
            for j in range(len(self.sol[i])):
                component_idx = self.sol[i][j][0]
                step_idx = self.sol[i][j][1]
                assert len(component_list[component_idx][step_idx]) == 0, 'component %s step %d appear more than one time!' % (self._idx_to_letter(component_idx), step_idx + 1)
                component_list[component_idx][step_idx] = [i, self.sol[i][j][2], self.sol[i][j][3]]
        for i in range(component_num):
            for j in range(len(component_list[i])):
                assert len(component_list[i][j]) != 0, 'component %s step %d missed!' % (self._idx_to_letter(i), j + 1)
        # 零件时序性、重复占用
        for i in range(component_num):
            now = 0
            for j in range(len(component_list[i])):
                assert component_list[i][j][1] >= now, \
                    'component %s step %d start time %d conflicts with last time %d!' % (self._idx_to_letter(i), j + 1, component_list[i][j][1], now)
                assert component_list[i][j][2] >= component_list[i][j][1], \
                    'component %s step %d end time %d conflicts with start time %d!' % (self._idx_to_letter(i), j + 1, component_list[i][j][2], component_list[i][j][1])
                now = component_list[i][j][2]
        # 零件加工机器正确性、时间正确性
        for i in range(component_num):
            for j in range(len(component_list[i])):
                flag = 0
                for k in range(len(component_info[i][j])):
                    if component_list[i][j][0] == component_info[i][j][k][0]:
                        flag = 1
                        assert component_list[i][j][2] - component_list[i][j][1] == component_info[i][j][k][1], \
                            'component_step %s%d producted by machine M%d will use time %d not end_time %d - start_time %d' % \
                                (self._idx_to_letter(i), j + 1, component_list[i][j][0] + 1, component_info[i][j][k][1], component_list[i][j][2], component_list[i][j][1])
                        break
                assert flag == 1, 'component_step %s%d can not be producted by machine M%d!' % (self._idx_to_letter(i), j + 1, component_list[i][j][0])
        if show_info:
            print('verify passed!')

    def get_finished_time(self):
        assert self.sol is not None, 'need load solution before use function get_finished_time()!'
        finished_time = 0
        for i in range(len(self.sol)):
            if len(self.sol[i]) > 0:
                finished_time = max(finished_time, self.sol[i][-1][3])
        return finished_time

    def score(self, is_verify=True):
        assert self.sol is not None, 'need load solution before score!'
        if is_verify:
            self.verify(show_info=True)
        print('finished time is:', self.get_finished_time())


if __name__ == '__main__':
    verifier = Verifier(data_path='data_final.txt')
    verifier.load_sol_from_file(data_path='data_final_best.out')
    verifier.score()
